use strict;
use DBI;
use DBD::ODBC;
use POSIX;
use Time::HiRes qw(time);
use Storable qw(dclone);
use List::Util qw(shuffle);
use List::MoreUtils qw/ uniq /;
use List::MoreUtils 'pairwise';

my $flagLowDim = 0;
my $iter = 0;

require 'CDS_FilterData.pl';

my ($NTDB_HD);

open (KEYINFO, '> NTDB_Keys.txt');
open (LOG, '> NTDB_Log.txt');

my $BASE_HD_FILE_NAME = 'NTDB_HD';


############################################### NTDB DATA ########################################################
my $dsn = 'dbi:ODBC:NTDBNEWDriver';
my ($username, $password) = ('trauma', 'trauma');

# Set connection parameters

# Connect to the database
my $ntdb = DBI -> connect($dsn,$username,$password);

# Preparing and executing sql query
my $sql = "EXEC sp_NTDBNEW_Imputation_ExtractRelevantColsFromCDS14";
print LOG "SQL COMMAND EXECUTED: $sql\n";

my $sth = $ntdb-> prepare($sql);
$sth -> execute();

my (%hUID, %hAGE, %hUID_GLASGOW, %hUID_AISCODE);
my (%hDEATH, %hGLASGOW, %hAISCODE);

#########################################
# $UID = PSU_CASEID_ACCYEAR_VEHNO_OCCNO #
#########################################

# Declare corresponding hash keys
my ($DEATH, $TREATMNT, $UID, $AGE, $PARUSE, $CHORIENT, $CHORIENTA, $SEATPOS, $SEATPOS_ROW, $SEATPOS_COL, $EJECTION, $GLASGOW, $AISCODE, $MANCOLL, $CLASS1, $CLASS2, $OBJCONT, $DVTOTAL, $DVEST, $SPLIMIT);


my ($INC_KEY, $AISPCODE_PREDOT, $DEMO_AGE, $DISCHARGE_HOSPDISP, $ECODE_ECODE, $ECODE_ECODE2, $VITALS_GCSEYE, $VITALS_GCSVERB, $VITALS_GCSMOT, $VITALS_GCSTOT, $ED_EDDISP, $ED_YOINJ, $OUTPUT);
my @aUID_NTDB;

$iter = 0;
while(($INC_KEY, $AISPCODE_PREDOT, $DEMO_AGE, $DISCHARGE_HOSPDISP, $ECODE_ECODE, $ECODE_ECODE2, $VITALS_GCSEYE, $VITALS_GCSVERB, $VITALS_GCSMOT, $VITALS_GCSTOT, $ED_EDDISP, $ED_YOINJ) = $sth -> fetchrow_array())
{
    push(@aUID_NTDB, $INC_KEY);
        
    $iter++;
    
    $INC_KEY = trim($INC_KEY);
    $AISPCODE_PREDOT = trim($AISPCODE_PREDOT);
    $DISCHARGE_HOSPDISP = trimIfEmpty($DISCHARGE_HOSPDISP);
    $ECODE_ECODE = trimIfEmpty($ECODE_ECODE);
    $ECODE_ECODE2 = trimIfEmpty($ECODE_ECODE2);
    $VITALS_GCSEYE = trimIfEmpty($VITALS_GCSEYE);
    $VITALS_GCSVERB = trimIfEmpty($VITALS_GCSVERB);
    $VITALS_GCSMOT = trimIfEmpty($VITALS_GCSMOT);
    $VITALS_GCSTOT = trimIfEmpty($VITALS_GCSTOT);
    $ED_EDDISP = trimIfEmpty($ED_EDDISP);
    
    ($VITALS_GCSEYE, $VITALS_GCSVERB, $VITALS_GCSMOT, $VITALS_GCSTOT) = filterGCS_NTDB_forCDS($VITALS_GCSEYE, $VITALS_GCSVERB, $VITALS_GCSMOT, $VITALS_GCSTOT);
    $OUTPUT = filterStatus_NTDB_forCDS($DISCHARGE_HOSPDISP, $ED_EDDISP);
    
#    print LOG "$iter: $INC_KEY, $OUTPUT, $AISPCODE_PREDOT, $DEMO_AGE, $DISCHARGE_HOSPDISP, $ECODE_ECODE, $ECODE_ECODE2, $VITALS_GCSTOT, $ED_EDDISP, $ED_YOINJ\n";
    
    $hUID{$INC_KEY} = 1;
    $hDEATH{$INC_KEY} = $OUTPUT;
    $hUID_AISCODE{$INC_KEY}{$AISPCODE_PREDOT} = 1;
    $hAGE{$INC_KEY} = $DEMO_AGE;    
    $hUID_GLASGOW{$INC_KEY}{$VITALS_GCSTOT} = 1;
}

@aUID_NTDB = sort(uniq(@aUID_NTDB));

foreach my $key (sort keys(%hUID)) {
    %hGLASGOW = assignHKeys(\%{$hUID_GLASGOW{$key}},\%hGLASGOW);
    %hAISCODE = assignHKeys(\%{$hUID_AISCODE{$key}},\%hAISCODE);
}

my (@aInds_NTDB_Dead, @aInds_NTDB_Alive);

my $counter = 0;

foreach my $key (@aUID_NTDB) {
    if($hDEATH{$key} == 1) {
        push(@aInds_NTDB_Dead, $counter);
    } else {
        push(@aInds_NTDB_Alive, $counter);
    }
    $counter++;
}

my @aUID = @aUID_NTDB;

# printing some counts
print LOG "Counts:\n------------------------------------------\n";
print LOG "\nGLASGOW\n";
foreach my $i (sort keys %hGLASGOW) {
    print LOG "$i $hGLASGOW{$i}\n";
}
print LOG "\nAISCODE\n";
foreach my $i (sort keys %hAISCODE) {
    print LOG "$i $hAISCODE{$i}\n";
}


# Note: 1=age, 2=gender, 3=sysbp, 4=resprate, 5=pulse
print KEYINFO "seq=1: Intercept\n";
print KEYINFO "seq=2: Age\n";
print KEYINFO "\n";

my $seqNum = 3;

# assign sequence number for TREATMNT.
#foreach my $i (sort keys %hTREATMNT) {
#    $hTREATMNT{$i}=$seqNum;
#    $seqNum++;        
#}
#print KEYINFO "TREATMNT Keys... ". (keys %hTREATMNT) ." keys\n";
#foreach my $i (sort keys %hTREATMNT) {
#    print KEYINFO "seq=$hTREATMNT{$i}: TREATMNT=$i\n";
#}
#print KEYINFO "\n";


#assign sequence number for GLASGOW
foreach my $i (sort keys %hGLASGOW){
    $hGLASGOW{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "GLASGOW Keys... ". (keys %hGLASGOW) ." keys\n";
foreach my $i (sort keys %hGLASGOW){
    print KEYINFO "seq=$hGLASGOW{$i}, GLASGOW=$i\n";
}
print KEYINFO "\n";

# assign sequence number for AISCODE
foreach my $i (sort keys %hAISCODE){
    $hAISCODE{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "AISCODE Keys... ". (keys %hAISCODE) ." keys\n";
foreach my $i (sort keys %hAISCODE){
    print KEYINFO "seq=$hAISCODE{$i}: AISCODE=$i\n";
}
print KEYINFO "\n";

#my faster implementation
my $countInt = 0;
my %hTMP;
my %hAISCODE_AISCODE;

my $startTime = time();
foreach my $key (sort keys %hUID_AISCODE)
{
    %hTMP = %{dclone(\%{$hUID_AISCODE{$key}})};
    foreach my $code1 (sort keys %hTMP)
    {
        delete($hTMP{$code1});  # to avoid [code1,code1] combinations
        foreach my $code2 (sort keys %hTMP)
        {
            if(!exists($hAISCODE_AISCODE{$code1}{$code2}))
            {
                $countInt++;
                print LOG "Processing two-way [AISCODE,AISCODE] interactions...$countInt\n";
                $hAISCODE_AISCODE{$code1}{$code2} = 1;
            }
        }
    }
}
foreach my $code1 (sort keys %hAISCODE_AISCODE)
{
    foreach my $code2 (sort keys %{$hAISCODE_AISCODE{$code1}})
    {
        $hAISCODE_AISCODE{$code1}{$code2} = $seqNum;
        $seqNum++;
    }
}
print KEYINFO "Two-way [AISCODE,AISCODE] Keys... $countInt keys\n";
foreach my $i (sort keys %hAISCODE_AISCODE)
{
    foreach my $j (sort keys %{$hAISCODE_AISCODE{$i}})
    {
        print KEYINFO "seq=$hAISCODE_AISCODE{$i}{$j}: [AISCODE,AISCODE]=$i, $j\n";
    }
}
print KEYINFO "\n";
my $runTime = time() - $startTime;
print LOG "Processed $countInt two-way [AISCODE,AISCODE] interactions.\n";
print LOG "Time taken = $runTime seconds.\n\n";


    my ($nNTDB_Alive, $nNTDB_Dead);
    $nNTDB_Alive = $#aInds_NTDB_Alive + 1;
    $nNTDB_Dead = $#aInds_NTDB_Dead + 1;
    
    my $HD_FILE_NAME = $BASE_HD_FILE_NAME . ".txt";
    
    my @aInds_selected = @aInds_NTDB_Alive;    
    push(@aInds_selected, @aInds_NTDB_Dead);

    my @aUID_selected = @aUID[@aInds_selected];
    
    open ($NTDB_HD, '> ' , $HD_FILE_NAME); # CDS and NTDB concatenated as: CDS + NTDB_Train + CDS_Test for imputation

    my $count = -1;
            
    foreach my $key (@aUID_selected){
#        print "$key\n";
        my $index=0;
        $count++;
    
        # DEATH
            print $NTDB_HD $hDEATH{$key} . " ";
        
        # Intercept    
        $index++;
        print $NTDB_HD "1:1 ";
        
        # AGE    
        $index++;
        print $NTDB_HD "$index:$hAGE{$key} ";
    
        # TREATMNT
        #foreach my $j (sort keys %{$hUID_TREATMNT{$key}}){
        #    if($j ne "NULL"){
        #        print $CDS_NTDB_HD $hTREATMNT{$j} . ":1 ";
        #        if($hDataType{$key} ne 'NTDB') {
        #            print $CDSonly_NTDB_LD $hTREATMNT{$j} . ":1 ";
        #        }
        #    }
        #    else{
        #        foreach my $k (sort keys %hTREATMNT){
        #            if($k ne "NULL"){
        #                print $CDS_NTDB_HD $hTREATMNT{$k} . ":NULL ";
        #                if($hDataType{$key} ne 'NTDB') {
        #                    print $CDSonly_NTDB_LD $hTREATMNT{$k} . ":NULL ";
        #                }
        #            }
        #        }
        #    }
        #}
        
        
        #GLASGOW
        foreach my $j (sort keys %{$hUID_GLASGOW{$key}}){
            if($j ne "NULL"){
                print $NTDB_HD $hGLASGOW{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hGLASGOW){
                    if($k ne "NULL"){
                        print $NTDB_HD $hGLASGOW{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #AISCODE
        foreach my $j (sort keys %{$hUID_AISCODE{$key}}){
            if($j ne "NULL"){
                print $NTDB_HD $hAISCODE{$j} . ":1 ";
            }
        }
        
        # Two-way [AISCODE,AISCODE] codes
        %hTMP = %{dclone(\%{$hUID_AISCODE{$key}})};
        foreach my $code1(sort keys %{$hUID_AISCODE{$key}})
            {
            delete($hTMP{$code1});		# to avoid [code1,code1] combinations
            foreach my $code2(sort keys %hTMP)
            {
                print $NTDB_HD $hAISCODE_AISCODE{$code1}{$code2} . ":1 ";
            }
        }
    
        print $NTDB_HD "\n";
    }
    close($NTDB_HD);


$ntdb->disconnect();
close(KEYINFO);
close(LOG);
